#!/usr/bin/python3
from abc import ABCMeta, abstractmethod
from typing import Any

import pandas as pd
from finta import TA


class Indicator(metaclass=ABCMeta):
    """"""

    @abstractmethod
    def cal(self, ohlc: pd.DataFrame) -> Any:
        pass


class MaVol(Indicator):
    """"""

    def __init__(self):
        self.lP = 10
        self.sP = 5
        self.name = 'MaVol'
        self.colum = 'volume'

    def cal(self, ohlc: pd.DataFrame) -> Any:
        if ohlc.shape[0] < self.lP:
            """"""
            return None
        lvo = TA.SMA(ohlc, self.lP, self.colum)
        svo = TA.SMA(ohlc, self.sP, self.colum)
        return pd.Series(lvo - svo, name='MaVol')


class MaCd(Indicator):
    """"""

    def __init__(self):
        """"""
        self.f = 12
        self.s = 26

    def cal(self, ohlc: pd.DataFrame) -> Any:
        if ohlc.shape[0] < self.s:
            """"""
            return None
        dat = TA.MACD(ohlc)
        return dat


class ArBr(Indicator):
    """"""

    def __init__(self):
        """"""
        self.w = 26

    def cal(self, ohlc: pd.DataFrame) -> Any:
        """"""
        if ohlc.shape[0] < self.w:
            """"""
            return None
        ohlc['ho'] = ohlc['high'] - ohlc['open']
        ohlc['ol'] = ohlc['open'] - ohlc['low']
        csy = ohlc['close'].shift(1)
        ohlc['hyc'] = (ohlc.high - csy).map(lambda x: max(x, 0))
        ohlc['ycl'] = (csy - ohlc.low).map(lambda x: max(x, 0))
        a0 = ohlc['ho'].rolling(window=self.w).sum() / ohlc['ol'].rolling(window=self.w).sum() * 100
        b0 = ohlc['hyc'].rolling(window=self.w).sum() / ohlc['ycl'].rolling(window=self.w).sum() * 100
        ar = pd.Series(a0, name="AR")
        br = pd.Series(b0, name="BR")
        return pd.concat([ar, br], axis=1)


class RSI(Indicator):
    """"""
    def __init__(self):
        self.w = 12

    def cal(self, ohlc: pd.DataFrame) -> pd.Series:
        if ohlc.shape[0] < self.w:
            """"""
            return None
        return TA.RSI(ohlc, period=self.w)